package com.manli.api.base.datasource;

import java.sql.SQLException;
import java.sql.Types;
import java.util.Arrays;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.druid.filter.FilterChain;
import com.alibaba.druid.filter.FilterEventAdapter;
import com.alibaba.druid.proxy.jdbc.ConnectionProxy;
import com.alibaba.druid.proxy.jdbc.JdbcParameter;
import com.alibaba.druid.proxy.jdbc.PreparedStatementProxy;
import com.alibaba.druid.proxy.jdbc.StatementProxy;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDeleteStatement;
import com.manli.api.base.exception.MyException;
import com.manli.api.enums.ResultEnums;
import com.manli.api.util.SqlInjectionCheckUtils;

public class MyDruidFilter extends FilterEventAdapter{
	
	Logger logger = LoggerFactory.getLogger(getClass());
	/**
	 * 数据库类型
	 */
	private String dbType = "mysql";
	/**
	 * 删表操作白名单
	 */
	private List<String> ignoreDeletTable = Arrays.asList("role_permission","major_branch_partner","user_link_unionid");
	
	@Override
	protected void statementExecuteBefore(StatementProxy statement, String sql) {
		logParameter(statement, sql);
		super.statementExecuteBefore(statement, sql);
	}

	@Override
	protected void statementExecuteUpdateBefore(StatementProxy statement, String sql) {
		// TODO Auto-generated method stub
		logParameter(statement, sql);
		super.statementExecuteUpdateBefore(statement, sql);
	}

	@Override
	protected void statementExecuteQueryBefore(StatementProxy statement, String sql) {
		// TODO Auto-generated method stub
		logParameter(statement , sql);
		super.statementExecuteQueryBefore(statement, sql);
	}
	
	private void logParameter(StatementProxy statement , String sql) {
		if (!(statement instanceof PreparedStatementProxy)) {
			return;
		}
		StringBuffer buf = new StringBuffer();
		buf.append(" Parameters : [");

		for (int i = 0, parametersSize = statement.getParametersSize(); i < parametersSize; ++i) {
			JdbcParameter parameter = statement.getParameter(i);
			if (i != 0) {
				buf.append(", ");
			}
			if (parameter == null) {
				continue;
			}

			int sqlType = parameter.getSqlType();
			Object value = parameter.getValue();
			switch (sqlType) {
			case Types.NULL:
				buf.append("NULL");
				break;
			default:
				buf.append(String.valueOf(value));
				break;
			}
		}
		buf.append("]");
		/**
		 * 防止sql注入
		 */
		injectionSqlCheck(sql,buf.toString());
	}
	/**
	 * 防止sql注入
	 */
	private void injectionSqlCheck(String sql , String params) {
		if(SqlInjectionCheckUtils.injectionSqlCheck(sql, params)) {
			logger.error("sql注入风险!!! sql["+sql+"]-params["+params+"]");
			throw new MyException(ResultEnums.SQL_INJECTION);
		}
	}
	
	/**
	 * 拦截解析sql
	 */
	@Override
	public PreparedStatementProxy connection_prepareStatement(FilterChain chain,
	      ConnectionProxy connection, String sql) throws SQLException {
		sql = SQLUtils.format(sql, dbType);// 缺省大写格式
	    List<SQLStatement> stmtList = SQLUtils.parseStatements(sql, dbType);
	    for(SQLStatement sqlStatement : stmtList) {
		    if (sql.toUpperCase().indexOf("DELETE")>-1) {
		    	MySqlDeleteStatement delete = (MySqlDeleteStatement)sqlStatement;
		    	String tableName = delete.getTableName().toString().replaceAll("`", "").toLowerCase();
		    	//过滤白名单
		    	if(!ignoreDeletTable.contains(tableName)) {
		    		throw new MyException(ResultEnums.SQL_DELETE_FORBIDDEN);
		    	}
		    }
		    if (sql.toUpperCase().indexOf("DROP")>-1) {
		    	logger.error("DROP语句"+sql);
		    	throw new MyException(ResultEnums.SQL_DROP_FORBIDDEN);
		    }
	    }
		return super.connection_prepareStatement(chain, connection, sql);
	}
}
